This is an R Markdown Notebook. When you execute code within the notebook, the results appear beneath the code.

Try executing this chunk by clicking the Run button within the chunk or by placing your cursor inside it and pressing Cmd+Shift+Enter.

plot(cars)

Add a new chunk by clicking the Insert Chunk button on the toolbar or by pressing Cmd+Option+I.

When you save the notebook, an HTML file containing the code and output will be saved alongside it (click the Preview button or press Cmd+Shift+K to preview the HTML file).

The preview shows you a rendered HTML copy of the contents of the editor. Consequently, unlike Knit, Preview does not run any R code chunks. Instead, the output of the chunk when it was last run in the editor is displayed.

**************************************

PART FOUR: CLASS EXERCISES *

**************************************

Jon Sadler - updated Mar 10th 2022

load in Libraries

library(car)
Loading required package: carData
library(tidyverse)
Registered S3 methods overwritten by 'dbplyr':
  method         from
  print.tbl_lazy     
  print.tbl_sql      
Warning in (function (kind = NULL, normal.kind = NULL, sample.kind = NULL)  :
  non-uniform 'Rounding' sampler used
── Attaching packages ─────────────────────────────────────────────── tidyverse 1.3.1 ──
✓ ggplot2 3.3.5     ✓ purrr   0.3.4
✓ tibble  3.1.6     ✓ dplyr   1.0.8
✓ tidyr   1.2.0     ✓ stringr 1.4.0
✓ readr   2.1.2     ✓ forcats 0.5.1
Warning in (function (kind = NULL, normal.kind = NULL, sample.kind = NULL)  :
  non-uniform 'Rounding' sampler used
── Conflicts ────────────────────────────────────────────────── tidyverse_conflicts() ──
x dplyr::filter() masks stats::filter()
x dplyr::lag()    masks stats::lag()
x dplyr::recode() masks car::recode()
x purrr::some()   masks car::some()
library(ggfortify)
library(scales) # You need this library to to access break formatting functions for log axes

Attaching package: ‘scales’

The following object is masked from ‘package:purrr’:

    discard

The following object is masked from ‘package:readr’:

    col_factor

#1. Linear Regression using the faithful dataset # look at the data in the base file

str(faithful)
'data.frame':   272 obs. of  2 variables:
 $ eruptions: num  3.6 1.8 3.33 2.28 4.53 ...
 $ waiting  : num  79 54 74 62 85 55 88 85 51 85 ...
faithful
View(faithful)

plot some pictures

scatterplot(eruptions ~ waiting, data = faithful)

Looks decent in terms of the boxplots - indicates normality and homogeneity of variance

Maybe an issue with linearity of the response to explanatory but we’ll have a look

Using ggplot

ggplot(faithful,aes(waiting,eruptions)) + geom_point() + geom_smooth(method=lm)
`geom_smooth()` using formula 'y ~ x'

Specify and examine linear model

summary(lm(eruptions ~ waiting, data = faithful))

Call:
lm(formula = eruptions ~ waiting, data = faithful)

Residuals:
     Min       1Q   Median       3Q      Max 
-1.29917 -0.37689  0.03508  0.34909  1.19329 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) -1.874016   0.160143  -11.70   <2e-16 ***
waiting      0.075628   0.002219   34.09   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.4965 on 270 degrees of freedom
Multiple R-squared:  0.8115,    Adjusted R-squared:  0.8108 
F-statistic:  1162 on 1 and 270 DF,  p-value: < 2.2e-16
anova(lm(eruptions ~ waiting, data = faithful))
Analysis of Variance Table

Response: eruptions
           Df  Sum Sq Mean Sq F value    Pr(>F)    
waiting     1 286.478 286.478  1162.1 < 2.2e-16 ***
Residuals 270  66.562   0.247                      
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

write the model to an object

faithful.lm <- lm(eruptions ~ waiting, data = faithful)

look at plots for validation

op <- par(mfrow = c(2, 2)) 
plot(faithful.lm)
par(op)

QQ-plot indicates normality

residuals v fitted suggests limited heterogeneity that is a result of two clumps of points, but it the residuals are evenly spread either side of the zero line.

Scale v location indicates homogeneity

Leverage plot indicates a few issues. We’ll leave it and come back to how to deal with this # in subsequent classes

same plots in ggfortify

autoplot(faithful.lm)

Last validation task; plot residuals against explanatory

plot(faithful.lm$resid ~ faithful$waiting,
     xlab = "Waiting time (mins)",
     ylab = "Model residuals")

Generally fine so we’ll go with it for the time being.

Decision will run with a linear model

# We’ll revisit this in a week or so to run another regression technique later in the course # plot model and add R-square etc

plot(eruptions ~ waiting, data = faithful,
     xlab = "Waiting time between eruptions (mins)",
     ylab = "Eruption duration (mins)",
     pch = 20, col = "grey", bg = "grey") # We've left the axes on
# add the regression line from the model (faithful.lm) using abline.....
abline(faithful.lm, col="black")
# add the equation
text(99,2, "eruptions = 0.0756waiting + -1.874", pos = 2, cex=0.65)
# add r-square value
text(99,1.75, expression(paste(R^2 == 0.8108)), pos = 2, cex = 0.6) # add in text using the expression/paste functions
# create a sequence of 1000 number spanning the range of humidities (min to max)
x <- seq(min(faithful$waiting), max(faithful$waiting), l=1000)  # notice this is an 'l' = length. NOT a 1!!!!!!!
#for each value of x, calculate the upper and lower 95% confidence
y<-predict(faithful.lm, data.frame(waiting=x), interval="c")
#plot the upper and lower 95% confidence limits
matlines(x,y, lty=3, col="black") # This function add the CIs, lty = line type (dashed)

plot with ggplot

p <- ggplot(faithful, aes(x=waiting, y=eruptions)) + 
  geom_point(col = "grey") +
  geom_smooth(method=lm, col = "black") + 
  annotate(geom = "text", x = 50, y = 6,
           label = "Eruptions = -0.076Waiting + -1.87\nAdj. R2 = 0.8108",
           hjust = 0)
p + xlab("Waiting time between eruptions (mins)") + ylab("Eruption duration (mins)") + theme_bw()
`geom_smooth()` using formula 'y ~ x'

Predict and plot with ggplot

add ‘fit’, ‘lwr’, and ‘upr’ columns to dataframe (generated by predict)

old.predict <- cbind(faithful, predict(faithful.lm, interval = 'confidence'))

plot the points (actual observations), regression line, and confidence interval

p <- ggplot(old.predict, aes(waiting,eruptions))
p <- p + geom_point()
p <- p + geom_line(aes(waiting, fit))
p <- p + geom_ribbon(aes(ymin=lwr,ymax=upr), alpha=0.3)
p

2. Mussel dataset using abundance as a response variable

load data file

Mussel <- read.csv(file.choose())

Look at it

glimpse(Mussel)
Rows: 25
Columns: 3
$ AREA    <dbl> 516.00, 469.06, 462.25, 938.60, 1357.15, 1773.66, 1686.01, 1786.29, 30…
$ SPECIES <int> 3, 7, 6, 8, 10, 9, 10, 11, 16, 9, 13, 14, 12, 14, 20, 22, 15, 20, 22, …
$ INDIV   <int> 18, 60, 57, 100, 48, 118, 148, 214, 225, 283, 380, 278, 338, 274, 569,…

Plot it to check for linearity

scatterplot(INDIV ~ AREA, data = Mussel)

This indicates that the data are not normaly disributed (especially AREA)

The abundance data don’t look too good either. Huge peak in the middle

might be outliers in both!!!!

Let’s fit a linear model nonetheless

mussel.lm <- lm(SPECIES ~ AREA, data = Mussel)
# look at it
summary(mussel.lm)

Call:
lm(formula = SPECIES ~ AREA, data = Mussel)

Residuals:
    Min      1Q  Median      3Q     Max 
-7.1964 -2.7521 -0.7509  1.2094  7.2148 

Coefficients:
             Estimate Std. Error t value Pr(>|t|)    
(Intercept) 9.856e+00  1.044e+00   9.441 2.24e-09 ***
AREA        6.593e-04  9.283e-05   7.102 3.10e-07 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 3.759 on 23 degrees of freedom
Multiple R-squared:  0.6868,    Adjusted R-squared:  0.6732 
F-statistic: 50.44 on 1 and 23 DF,  p-value: 3.102e-07

Now check assumption by using R’s inbuilt model validation plot defaults

set graphics parameters because we want all the plots on one graphic

autoplot(mussel.lm)

Residuals v Fitted indicate a problem. It’s wedge shaped and humped!

qqplot is a bit dodgy but might be okay

Scale-Location plot indicates a wedge

Cook distance / leverage looks okay - but there are some large values in area

FINAL VALIDATION TASK - residuals against explanatory variable

plot(mussel.lm$resid ~ Mussel$AREA,
     xlab = "Mussel bed Area", 
     ylab = "Residuals")

Some code for ggplot to do the same thing…..

ggplot(fortify(mussel.lm, Mussel), aes(AREA, .stdresid)) +
  geom_point() + geom_smooth(se = TRUE)
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

This indicates a few large values and a slight wedge due to numerous small patches

Conclusion we reject the model

So what do we do?

We can linearise the explanatory variables by transforming them and re-run the model

I am not a fan of this - we’ll look at other approaches next week!

and repeat the validation

Let’s fit a linear model nonetheless

mussel.lm1 <- lm(SPECIES ~ log10(AREA), data = Mussel)
# look at it
summary(mussel.lm1)

Call:
lm(formula = SPECIES ~ log10(AREA), data = Mussel)

Residuals:
    Min      1Q  Median      3Q     Max 
-5.7204 -1.7227  0.3603  1.8136  4.2430 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept)  -25.731      3.777  -6.812 6.02e-07 ***
log10(AREA)   11.226      1.030  10.895 1.48e-10 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 2.707 on 23 degrees of freedom
Multiple R-squared:  0.8377,    Adjusted R-squared:  0.8306 
F-statistic: 118.7 on 1 and 23 DF,  p-value: 1.481e-10

Now check assumption by using R’s inbuilt model validation plot defaults

set graphics parameters because we want all the plots on one graphic

autoplot(mussel.lm1)

Residuals v Fitted are better but there is still a bit of wedge at higher fitted values

qqplot is a better

Scale-Location plot indicates a slight wedge with higher values

Cook distance / leverage looks improved

FINAL VALIDATION TASK - residuals against explanatory variable

ggplot(fortify(mussel.lm1, Mussel), aes(AREA, .stdresid)) +
  geom_point() + geom_smooth(se = FALSE)
`geom_smooth()` using method = 'loess' and formula 'y ~ x'

This indicates a few large values and a slight wedge due to numerous small patches

Conclusion we reject the model

Try log10 on the response - not unusual with abundance data.

There are no zeros so we don’t need an offset of 0.01 or something similar

Let’s fit a linear model nonetheless

mussel.lm2 <- lm(log10(INDIV) ~ log10(AREA), data = Mussel)
# look at it
summary(mussel.lm2)

Call:
lm(formula = log10(INDIV) ~ log10(AREA), data = Mussel)

Residuals:
     Min       1Q   Median       3Q      Max 
-0.43355 -0.06464  0.02219  0.11178  0.26818 

Coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) -0.57601    0.25904  -2.224   0.0363 *  
log10(AREA)  0.83492    0.07066  11.816 3.01e-11 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 0.1856 on 23 degrees of freedom
Multiple R-squared:  0.8586,    Adjusted R-squared:  0.8524 
F-statistic: 139.6 on 1 and 23 DF,  p-value: 3.007e-11

Now check assumption

autoplot(mussel.lm2)

Residuals v Fitted are much better

qqplot is okay - slight issue on lower values

Scale-Location plot is fine

Cook distance / leverage looks okay

FINAL VALIDATION TASK - residuals against explanatory variable

ggplot(fortify(mussel.lm2, Mussel), aes(AREA, .stdresid)) +
  geom_point() 

This is better but still a slight hump

Conclusion we accept the model

plot the final model in ggplot…

p <- ggplot(Mussel, aes(AREA,INDIV)) + 
  geom_point(col = "grey") +
  geom_smooth(method=lm, col = "black") + 
  annotate(geom = "text", x = 1000, y = 30,
           label = "log10(INDIV) = 0.835 + log10(AREA) - 0.576\n[Adj. R2 = 0.8108]", hjust = 0)  # adds text (NOTE \n means start new line)
p + scale_x_continuous(trans = 'log10') + scale_y_continuous(trans = 'log10') + # These commands scale the axes
  annotation_logticks(sides="lb") # This adds log10 tick marks
`geom_smooth()` using formula 'y ~ x'

NOTE: the log axes use the Scales library [see above]

#Plot the graph add equations in base R

plot(log10(INDIV) ~ log10(AREA), data = Mussel,
     xlab = "Log Mussel clump area (mm2)",
     ylab = "Log Number of Individuals",
     pch = 21, col = "grey", bg = "grey") # We've left the axes on
# add the regression line from the model (faithful.lm) using abline.....
abline(mussel.lm2, col="black")
# add the equation
text(4.0, 1.4, expression(paste(Log[10], "INDIV = 0.835", log[10], "AREA - 0.576", pos = 2)), cex = .7)
# add r-square value
text(4.0, 1.3, expression(paste(R^2 == 0.852)), cex = .7) # add in text using the expression/paste functions
# create a sequence of 1000 number spanning the range of humidities (min to max)
x <- seq(min(Mussel$AREA), max(Mussel$AREA), l=1000)  # notice this is an 'l' = length. NOT a 1!!!!!!!
#for each value of x, calculate the upper and lower 95% confidence
y<-predict(mussel.lm2, data.frame(AREA=x), interval="c")
#plot the upper and lower 95% confidence limits
matlines(log10(x),y, lty=3, col="black") # This function add the CIs, lty = line type (dashed) 

add in ggplot code….

p <- ggplot(Mussel, aes(x=log10(AREA), y=log10(INDIV))) + 
  geom_point(col = "blue") +
  geom_smooth(method=lm, col = "black") + 
  annotate(geom = "text", x = 2.5, y = 3,
           label = "Log10INDIV = 0.835 + log10AREA - 0.576\nAdj. R2 = 0.852",
           hjust = 0)
p + xlab("Log Mussel clump area (mm2)") + ylab("Log number of individuals")
`geom_smooth()` using formula 'y ~ x'

3. ANCOVA on compensation dataset

Just so you have a frame of reference going forward;

the compensation data are about the production of fruit (apples, kg)

on rootstocks of different widths (mm; the tops are grafted onto rootstocks).

Furthermore, some trees are in parts of the orchard that allow grazing by cattle,

and others are in parts free from grazing. Grazing may reduce the amount of grass,

which might compete with the apple trees for resources.

Load file

Compensation <- read.csv(file.choose())

look at data

str(Compensation)
'data.frame':   40 obs. of  3 variables:
 $ Root   : num  6.22 6.49 4.92 5.13 5.42 ...
 $ Fruit  : num  59.8 61 14.7 19.3 34.2 ...
 $ Grazing: Factor w/ 2 levels "Grazed","Ungrazed": 2 2 2 2 2 2 2 2 2 2 ...
Compensation$Grazing <- as.factor(Compensation$Grazing) # We need this to be a factor for an ANCOVA

Plot it

# Plot it....
plot(Fruit ~ Root, data = Compensation, pch = 19,cex = 1.5,
     col = c("Black", "Red")[Compensation$Grazing],
     xlab = list("Root biomass (mm)", cex = 1.2),
     ylab = list("Fruit Production (kg)", cex = 1.2))
# Now add a legend
legend(5, 115, legend = c("Grazed", "Ungrazed"),
       col = c("black", "red"), pch = 19)

Or in coplot

coplot(Root~ Fruit | Grazing, data =Compensation) # Grazed plants have higher root biomass. 

You can do this is lattice too

boxplot(Root ~ Grazing, data = Compensation) # These look fine

boxplot(Fruit ~ Grazing, data = Compensation)# These look fine

You might also do some QQ-plots here…..or plot to check homogeneity of variances

but we’ll leave that for validation….

Run ANCOVA

Compensation.lm <- lm(Fruit ~  Grazing*Root, data=Compensation) 

Validate model to check assumptions

autoplot(Compensation.lm)

This looks pretty decent. Slight concern over QQ-plot but it’s not a massive problem.

#Look at model outcomes

anova(Compensation.lm)
Analysis of Variance Table

Response: Fruit
             Df  Sum Sq Mean Sq  F value    Pr(>F)    
Grazing       1  2910.4  2910.4  62.3795 2.262e-09 ***
Root          1 19148.9 19148.9 410.4201 < 2.2e-16 ***
Grazing:Root  1     4.8     4.8   0.1031      0.75    
Residuals    36  1679.6    46.7                       
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Anova shows that both Root and Fruit are significant terms

But that the interaction isn’t….

summary(Compensation.lm) 

Call:
lm(formula = Fruit ~ Grazing * Root, data = Compensation)

Residuals:
     Min       1Q   Median       3Q      Max 
-17.3177  -2.8320   0.1247   3.8511  17.1313 

Coefficients:
                     Estimate Std. Error t value Pr(>|t|)    
(Intercept)          -125.173     12.811  -9.771 1.15e-11 ***
GrazingUngrazed        30.806     16.842   1.829   0.0757 .  
Root                   23.240      1.531  15.182  < 2e-16 ***
GrazingUngrazed:Root    0.756      2.354   0.321   0.7500    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 6.831 on 36 degrees of freedom
Multiple R-squared:  0.9293,    Adjusted R-squared:  0.9234 
F-statistic: 157.6 on 3 and 36 DF,  p-value: < 2.2e-16

Data indicate fruit differs by grazing

No interaction term i.e. slope for factor Grazing are the same

Look at the example in the lecture 6 to figure out the intercept and slope differences, but here we go:

The intercept (first row in the summary output) is the intercept for grazed samples because grazed (i.e G)

comes before ungrazed (i.e. U) in the alphabet and R uses an alphanumeric call on factor data.

The 2nd line GrazingUngrazed is the difference in the intercepts. So Ungrazed is 30.806 larger. Meaning 30.8 more seeds are produced by grazed plants

Calculate the intercept for Ungrazed

-125.173  + 30.806 # = -94.367
[1] -94.367

the third line is slope for root

the fourth line GrazingUngrazed:Root is the difference in slopes between Grazed and Ungrazed = 0.756, which is tiny

the coefficients show this….

coef(Compensation.lm)
         (Intercept)      GrazingUngrazed                 Root GrazingUngrazed:Root 
        -125.1730569           30.8057049           23.2403732            0.7560338 

Now lets add lines to the graphs. We can do it many ways - so here is another one!

Route one - using abline

plot(Fruit ~ Root, data = Compensation, pch = 19,cex = 1.5,
     col = c("Black", "Red")[Compensation$Grazing],
     xlab = list("Root biomass (mm)", cex = 1.2),
     ylab = list("Fruit production (kg)", cex = 1.2))
# Now add a legend
legend(5, 115, legend = c("Grazed", "Ungrazed"),
       col = c("black", "red"), pch = 19)
# add ablines....we'll do it manually using the slopes and intercepts but you can use coeff7() see below.
abline(-125.173, 23.240)
abline(-125.173+30.805, 23.240+0.756, col= "red")

Plot using coefficients

Compensation.lm$coeff[1] # regression coefficient for grazed intercept
(Intercept) 
  -125.1731 
Compensation.lm$coeff[2] # regression coefficient for grazed slope
GrazingUngrazed 
        30.8057 
Compensation.lm$coeff[3] # regression coefficient for diff in grazed/ungrazed intercept
    Root 
23.24037 
Compensation.lm$coeff[4] # regression coefficient for diff in grazed/ungrazed slope
GrazingUngrazed:Root 
           0.7560338 
plot(Fruit ~ Root, data = Compensation, pch = 19,cex = 1.5,
     col = c("Black", "Red")[Compensation$Grazing],
     xlab = list("Root biomass (mm)", cex = 1.2),
     ylab = list("Fruit Production (kg)", cex = 1.2))
# Now add a legend
legend(5, 115, legend = c("Grazed", "Ungrazed"),
       col = c("black", "red"), pch = 19)
# add ablines....using coefficients - coeff()
abline(coef(Compensation.lm)[1], coef(Compensation.lm)[3]) 
# Now add the summer regression line
abline(coef(Compensation.lm)[1] + coef(Compensation.lm)[2], 
       coef(Compensation.lm)[3] + coef(Compensation.lm)[4], 
       col = "red")

do some prediction….and plot….this is yet another way of doing it

#produce base plot

xs <- seq(0, 12, l = 100)
plot(Fruit ~ Root, data = Compensation, xlab = "Root biomass (mm)", ylab = "Fruit Production (kg)")
# Plot the points and predicted trends (using se)
points(Fruit ~ Root, data = Compensation, subset = Grazing == "Grazed", pch = 19)
pred <- predict(Compensation.lm, type = "response", se = TRUE, newdata = data.frame(Root = xs, Grazing = "Grazed", Root = mean(Compensation$Root)))
lines(pred$fit ~ xs)
points(Fruit ~ Root, data = Compensation, subset = Grazing == "Ungrazed", pch = 19, col = "red")
pred <- predict(Compensation.lm, type = "response", se = TRUE, newdata = data.frame(Root = xs, Grazing = "Ungrazed", Root = mean(Compensation$Root)))
lines(pred$fit ~ xs, col = "red")
legend("topleft", legend = c("Grazed", "Ungrazed"), pch = c(19, 19), col = c("red","black"), title = "Fruit Production", bty = "n")
box(bty = "l")

LS0tCnRpdGxlOiAiTGluZWFyIFJlZ3Jlc3Npb24gQ29kZSB3YWxrdGhyb3VnaCIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKVGhpcyBpcyBhbiBbUiBNYXJrZG93bl0oaHR0cDovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbSkgTm90ZWJvb2suIFdoZW4geW91IGV4ZWN1dGUgY29kZSB3aXRoaW4gdGhlIG5vdGVib29rLCB0aGUgcmVzdWx0cyBhcHBlYXIgYmVuZWF0aCB0aGUgY29kZS4gCgpUcnkgZXhlY3V0aW5nIHRoaXMgY2h1bmsgYnkgY2xpY2tpbmcgdGhlICpSdW4qIGJ1dHRvbiB3aXRoaW4gdGhlIGNodW5rIG9yIGJ5IHBsYWNpbmcgeW91ciBjdXJzb3IgaW5zaWRlIGl0IGFuZCBwcmVzc2luZyAqQ21kK1NoaWZ0K0VudGVyKi4gCgpgYGB7cn0KcGxvdChjYXJzKQpgYGAKCkFkZCBhIG5ldyBjaHVuayBieSBjbGlja2luZyB0aGUgKkluc2VydCBDaHVuayogYnV0dG9uIG9uIHRoZSB0b29sYmFyIG9yIGJ5IHByZXNzaW5nICpDbWQrT3B0aW9uK0kqLgoKV2hlbiB5b3Ugc2F2ZSB0aGUgbm90ZWJvb2ssIGFuIEhUTUwgZmlsZSBjb250YWluaW5nIHRoZSBjb2RlIGFuZCBvdXRwdXQgd2lsbCBiZSBzYXZlZCBhbG9uZ3NpZGUgaXQgKGNsaWNrIHRoZSAqUHJldmlldyogYnV0dG9uIG9yIHByZXNzICpDbWQrU2hpZnQrSyogdG8gcHJldmlldyB0aGUgSFRNTCBmaWxlKS4gCgpUaGUgcHJldmlldyBzaG93cyB5b3UgYSByZW5kZXJlZCBIVE1MIGNvcHkgb2YgdGhlIGNvbnRlbnRzIG9mIHRoZSBlZGl0b3IuIENvbnNlcXVlbnRseSwgdW5saWtlICpLbml0KiwgKlByZXZpZXcqIGRvZXMgbm90IHJ1biBhbnkgUiBjb2RlIGNodW5rcy4gSW5zdGVhZCwgdGhlIG91dHB1dCBvZiB0aGUgY2h1bmsgd2hlbiBpdCB3YXMgbGFzdCBydW4gaW4gdGhlIGVkaXRvciBpcyBkaXNwbGF5ZWQuCgojICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqCiMgUEFSVCBGT1VSOiBDTEFTUyBFWEVSQ0lTRVMgICAgICAgICAgICoKIyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgojIEpvbiBTYWRsZXIgLSB1cGRhdGVkIE1hciAxMHRoIDIwMjIKCmxvYWQgaW4gTGlicmFyaWVzCmBgYHtyfQpsaWJyYXJ5KGNhcikKbGlicmFyeSh0aWR5dmVyc2UpCmxpYnJhcnkoZ2dmb3J0aWZ5KQpsaWJyYXJ5KHNjYWxlcykgIyBZb3UgbmVlZCB0aGlzIGxpYnJhcnkgdG8gdG8gYWNjZXNzIGJyZWFrIGZvcm1hdHRpbmcgZnVuY3Rpb25zIGZvciBsb2cgYXhlcwpgYGAKCiMxLiBMaW5lYXIgUmVncmVzc2lvbiB1c2luZyB0aGUgZmFpdGhmdWwgZGF0YXNldAojIGxvb2sgYXQgdGhlIGRhdGEgaW4gdGhlIGJhc2UgZmlsZQpgYGB7cn0Kc3RyKGZhaXRoZnVsKQpmYWl0aGZ1bApWaWV3KGZhaXRoZnVsKQpgYGAKCiMgcGxvdCBzb21lIHBpY3R1cmVzCmBgYHtyfQpzY2F0dGVycGxvdChlcnVwdGlvbnMgfiB3YWl0aW5nLCBkYXRhID0gZmFpdGhmdWwpCmBgYAoKIyBMb29rcyBkZWNlbnQgaW4gdGVybXMgb2YgdGhlIGJveHBsb3RzIC0gaW5kaWNhdGVzIG5vcm1hbGl0eSBhbmQgaG9tb2dlbmVpdHkgb2YgdmFyaWFuY2UKIyBNYXliZSBhbiBpc3N1ZSB3aXRoIGxpbmVhcml0eSBvZiB0aGUgcmVzcG9uc2UgdG8gZXhwbGFuYXRvcnkgYnV0IHdlJ2xsIGhhdmUgYSBsb29rCgojIFVzaW5nIGdncGxvdApgYGB7cn0KZ2dwbG90KGZhaXRoZnVsLGFlcyh3YWl0aW5nLGVydXB0aW9ucykpICsgZ2VvbV9wb2ludCgpICsgZ2VvbV9zbW9vdGgobWV0aG9kPWxtKQpgYGAKCiMgU3BlY2lmeSBhbmQgZXhhbWluZSBsaW5lYXIgbW9kZWwKYGBge3J9CnN1bW1hcnkobG0oZXJ1cHRpb25zIH4gd2FpdGluZywgZGF0YSA9IGZhaXRoZnVsKSkKYW5vdmEobG0oZXJ1cHRpb25zIH4gd2FpdGluZywgZGF0YSA9IGZhaXRoZnVsKSkKYGBgCiMgd3JpdGUgdGhlIG1vZGVsIHRvIGFuIG9iamVjdApgYGB7cn0KZmFpdGhmdWwubG0gPC0gbG0oZXJ1cHRpb25zIH4gd2FpdGluZywgZGF0YSA9IGZhaXRoZnVsKQpgYGAKCiMgbG9vayBhdCBwbG90cyBmb3IgdmFsaWRhdGlvbgpgYGB7cn0Kb3AgPC0gcGFyKG1mcm93ID0gYygyLCAyKSkgCnBsb3QoZmFpdGhmdWwubG0pCnBhcihvcCkKYGBgCiMgUVEtcGxvdCBpbmRpY2F0ZXMgbm9ybWFsaXR5CiMgcmVzaWR1YWxzIHYgZml0dGVkIHN1Z2dlc3RzIGxpbWl0ZWQgaGV0ZXJvZ2VuZWl0eSB0aGF0IGlzIGEgcmVzdWx0IG9mIHR3byBjbHVtcHMgb2YgcG9pbnRzLCBidXQgaXQgdGhlIHJlc2lkdWFscyBhcmUgZXZlbmx5IHNwcmVhZCBlaXRoZXIgc2lkZSBvZiB0aGUgemVybyBsaW5lLgojIFNjYWxlIHYgbG9jYXRpb24gaW5kaWNhdGVzIGhvbW9nZW5laXR5CiMgTGV2ZXJhZ2UgcGxvdCBpbmRpY2F0ZXMgYSBmZXcgaXNzdWVzLiBXZSdsbCBsZWF2ZSBpdCBhbmQgY29tZSBiYWNrIHRvIGhvdyB0byBkZWFsIHdpdGggdGhpcyAjIGluIHN1YnNlcXVlbnQgY2xhc3NlcwoKIyBzYW1lIHBsb3RzIGluIGdnZm9ydGlmeQoKYGBge3J9CmF1dG9wbG90KGZhaXRoZnVsLmxtKQpgYGAKCiMgTGFzdCB2YWxpZGF0aW9uIHRhc2s7IHBsb3QgcmVzaWR1YWxzIGFnYWluc3QgZXhwbGFuYXRvcnkKYGBge3J9CnBsb3QoZmFpdGhmdWwubG0kcmVzaWQgfiBmYWl0aGZ1bCR3YWl0aW5nLAogICAgIHhsYWIgPSAiV2FpdGluZyB0aW1lIChtaW5zKSIsCiAgICAgeWxhYiA9ICJNb2RlbCByZXNpZHVhbHMiKQpgYGAKCiMgR2VuZXJhbGx5IGZpbmUgc28gd2UnbGwgZ28gd2l0aCBpdCBmb3IgdGhlIHRpbWUgYmVpbmcuIAoKIyBEZWNpc2lvbiB3aWxsIHJ1biB3aXRoIGEgbGluZWFyIG1vZGVsCiPCoFdlJ2xsIHJldmlzaXQgdGhpcyBpbiBhIHdlZWsgb3Igc28gdG8gcnVuIGFub3RoZXIgcmVncmVzc2lvbiB0ZWNobmlxdWUgbGF0ZXIgaW4gdGhlIGNvdXJzZQojIHBsb3QgbW9kZWwgYW5kIGFkZCBSLXNxdWFyZSBldGMKYGBge3J9CnBsb3QoZXJ1cHRpb25zIH4gd2FpdGluZywgZGF0YSA9IGZhaXRoZnVsLAogICAgIHhsYWIgPSAiV2FpdGluZyB0aW1lIGJldHdlZW4gZXJ1cHRpb25zIChtaW5zKSIsCiAgICAgeWxhYiA9ICJFcnVwdGlvbiBkdXJhdGlvbiAobWlucykiLAogICAgIHBjaCA9IDIwLCBjb2wgPSAiZ3JleSIsIGJnID0gImdyZXkiKSAjIFdlJ3ZlIGxlZnQgdGhlIGF4ZXMgb24KIyBhZGQgdGhlIHJlZ3Jlc3Npb24gbGluZSBmcm9tIHRoZSBtb2RlbCAoZmFpdGhmdWwubG0pIHVzaW5nIGFibGluZS4uLi4uCmFibGluZShmYWl0aGZ1bC5sbSwgY29sPSJibGFjayIpCiMgYWRkIHRoZSBlcXVhdGlvbgp0ZXh0KDk5LDIsICJlcnVwdGlvbnMgPSAwLjA3NTZ3YWl0aW5nICsgLTEuODc0IiwgcG9zID0gMiwgY2V4PTAuNjUpCiMgYWRkIHItc3F1YXJlIHZhbHVlCnRleHQoOTksMS43NSwgZXhwcmVzc2lvbihwYXN0ZShSXjIgPT0gMC44MTA4KSksIHBvcyA9IDIsIGNleCA9IDAuNikgIyBhZGQgaW4gdGV4dCB1c2luZyB0aGUgZXhwcmVzc2lvbi9wYXN0ZSBmdW5jdGlvbnMKIyBjcmVhdGUgYSBzZXF1ZW5jZSBvZiAxMDAwIG51bWJlciBzcGFubmluZyB0aGUgcmFuZ2Ugb2YgaHVtaWRpdGllcyAobWluIHRvIG1heCkKeCA8LSBzZXEobWluKGZhaXRoZnVsJHdhaXRpbmcpLCBtYXgoZmFpdGhmdWwkd2FpdGluZyksIGw9MTAwMCkgICMgbm90aWNlIHRoaXMgaXMgYW4gJ2wnID0gbGVuZ3RoLiBOT1QgYSAxISEhISEhIQojZm9yIGVhY2ggdmFsdWUgb2YgeCwgY2FsY3VsYXRlIHRoZSB1cHBlciBhbmQgbG93ZXIgOTUlIGNvbmZpZGVuY2UKeTwtcHJlZGljdChmYWl0aGZ1bC5sbSwgZGF0YS5mcmFtZSh3YWl0aW5nPXgpLCBpbnRlcnZhbD0iYyIpCiNwbG90IHRoZSB1cHBlciBhbmQgbG93ZXIgOTUlIGNvbmZpZGVuY2UgbGltaXRzCm1hdGxpbmVzKHgseSwgbHR5PTMsIGNvbD0iYmxhY2siKSAjIFRoaXMgZnVuY3Rpb24gYWRkIHRoZSBDSXMsIGx0eSA9IGxpbmUgdHlwZSAoZGFzaGVkKQoKYGBgCiMgIHBsb3Qgd2l0aCBnZ3Bsb3QKYGBge3J9CnAgPC0gZ2dwbG90KGZhaXRoZnVsLCBhZXMoeD13YWl0aW5nLCB5PWVydXB0aW9ucykpICsgCiAgZ2VvbV9wb2ludChjb2wgPSAiZ3JleSIpICsKICBnZW9tX3Ntb290aChtZXRob2Q9bG0sIGNvbCA9ICJibGFjayIpICsgCiAgYW5ub3RhdGUoZ2VvbSA9ICJ0ZXh0IiwgeCA9IDUwLCB5ID0gNiwKICAgICAgICAgICBsYWJlbCA9ICJFcnVwdGlvbnMgPSAtMC4wNzZXYWl0aW5nICsgLTEuODdcbkFkai4gUjIgPSAwLjgxMDgiLAogICAgICAgICAgIGhqdXN0ID0gMCkKcCArIHhsYWIoIldhaXRpbmcgdGltZSBiZXR3ZWVuIGVydXB0aW9ucyAobWlucykiKSArIHlsYWIoIkVydXB0aW9uIGR1cmF0aW9uIChtaW5zKSIpICsgdGhlbWVfYncoKQpgYGAKCiMgUHJlZGljdCBhbmQgcGxvdCB3aXRoIGdncGxvdAoKIyBhZGQgJ2ZpdCcsICdsd3InLCBhbmQgJ3VwcicgY29sdW1ucyB0byBkYXRhZnJhbWUgKGdlbmVyYXRlZCBieSBwcmVkaWN0KQpgYGB7cn0Kb2xkLnByZWRpY3QgPC0gY2JpbmQoZmFpdGhmdWwsIHByZWRpY3QoZmFpdGhmdWwubG0sIGludGVydmFsID0gJ2NvbmZpZGVuY2UnKSkKYGBgCiMgcGxvdCB0aGUgcG9pbnRzIChhY3R1YWwgb2JzZXJ2YXRpb25zKSwgcmVncmVzc2lvbiBsaW5lLCBhbmQgY29uZmlkZW5jZSBpbnRlcnZhbApgYGB7cn0KcCA8LSBnZ3Bsb3Qob2xkLnByZWRpY3QsIGFlcyh3YWl0aW5nLGVydXB0aW9ucykpCnAgPC0gcCArIGdlb21fcG9pbnQoKQpwIDwtIHAgKyBnZW9tX2xpbmUoYWVzKHdhaXRpbmcsIGZpdCkpCnAgPC0gcCArIGdlb21fcmliYm9uKGFlcyh5bWluPWx3cix5bWF4PXVwciksIGFscGhhPTAuMykKcApgYGAKIyAyLiBNdXNzZWwgZGF0YXNldCB1c2luZyBhYnVuZGFuY2UgYXMgYSByZXNwb25zZSB2YXJpYWJsZQojIGxvYWQgZGF0YSBmaWxlCmBgYHtyfQpNdXNzZWwgPC0gcmVhZC5jc3YoZmlsZS5jaG9vc2UoKSkKYGBgCiMgTG9vayBhdCBpdApgYGB7cn0KZ2xpbXBzZShNdXNzZWwpCmBgYAoKUGxvdCBpdCB0byBjaGVjayBmb3IgbGluZWFyaXR5CmBgYHtyfQpzY2F0dGVycGxvdChJTkRJViB+IEFSRUEsIGRhdGEgPSBNdXNzZWwpCmBgYAojIFRoaXMgaW5kaWNhdGVzIHRoYXQgdGhlIGRhdGEgYXJlIG5vdCBub3JtYWx5IGRpc3JpYnV0ZWQgKGVzcGVjaWFsbHkgQVJFQSkKIyBUaGUgYWJ1bmRhbmNlIGRhdGEgZG9uJ3QgbG9vayB0b28gZ29vZCBlaXRoZXIuIEh1Z2UgcGVhayBpbiB0aGUgbWlkZGxlCiMgbWlnaHQgYmUgb3V0bGllcnMgaW4gYm90aCEhISEKCiMgTGV0J3MgZml0IGEgbGluZWFyIG1vZGVsIG5vbmV0aGVsZXNzCmBgYHtyfQptdXNzZWwubG0gPC0gbG0oU1BFQ0lFUyB+IEFSRUEsIGRhdGEgPSBNdXNzZWwpCiMgbG9vayBhdCBpdApzdW1tYXJ5KG11c3NlbC5sbSkKYGBgCiMgQXJlYSBsb29rcyB0byBzaWduaWZpY2FudGx5IHJlbGF0ZWQgdG8gdGhlIG51bWJlciBvZiBtdXNzZWxzCiMgTm93IGNoZWNrIGFzc3VtcHRpb24gYnkgdXNpbmcgUidzIGluYnVpbHQgbW9kZWwgdmFsaWRhdGlvbiBwbG90IGRlZmF1bHRzCiMgc2V0IGdyYXBoaWNzIHBhcmFtZXRlcnMgYmVjYXVzZSB3ZSB3YW50IGFsbCB0aGUgcGxvdHMgb24gb25lIGdyYXBoaWMKYGBge3J9CmF1dG9wbG90KG11c3NlbC5sbSkKYGBgCiMgUmVzaWR1YWxzIHYgRml0dGVkIGluZGljYXRlIGEgcHJvYmxlbS4gSXQncyB3ZWRnZSBzaGFwZWQgYW5kIGh1bXBlZCEKIyBxcXBsb3QgaXMgYSBiaXQgZG9kZ3kgYnV0IG1pZ2h0IGJlIG9rYXkKIyBTY2FsZS1Mb2NhdGlvbiBwbG90IGluZGljYXRlcyBhIHdlZGdlCiMgQ29vayBkaXN0YW5jZSAvIGxldmVyYWdlIGxvb2tzIG9rYXkgLSBidXQgdGhlcmUgYXJlIHNvbWUgbGFyZ2UgdmFsdWVzIGluIGFyZWEKCiMgRklOQUwgVkFMSURBVElPTiBUQVNLIC0gcmVzaWR1YWxzIGFnYWluc3QgZXhwbGFuYXRvcnkgdmFyaWFibGUKYGBge3J9CnBsb3QobXVzc2VsLmxtJHJlc2lkIH4gTXVzc2VsJEFSRUEsCiAgICAgeGxhYiA9ICJNdXNzZWwgYmVkIEFyZWEiLCAKICAgICB5bGFiID0gIlJlc2lkdWFscyIpCmBgYAojIFNvbWUgY29kZSBmb3IgZ2dwbG90IHRvIGRvIHRoZSBzYW1lIHRoaW5nLi4uLi4KYGBge3J9CmdncGxvdChmb3J0aWZ5KG11c3NlbC5sbSwgTXVzc2VsKSwgYWVzKEFSRUEsIC5zdGRyZXNpZCkpICsKICBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aChzZSA9IFRSVUUpCmBgYAojIFRoaXMgaW5kaWNhdGVzIGEgZmV3IGxhcmdlIHZhbHVlcyBhbmQgYSBzbGlnaHQgd2VkZ2UgZHVlIHRvIG51bWVyb3VzIHNtYWxsIHBhdGNoZXMKIyBDb25jbHVzaW9uIHdlIHJlamVjdCB0aGUgbW9kZWwKCiMgU28gd2hhdCBkbyB3ZSBkbz8KIyBXZSBjYW4gbGluZWFyaXNlIHRoZSBleHBsYW5hdG9yeSB2YXJpYWJsZXMgYnkgdHJhbnNmb3JtaW5nIHRoZW0gYW5kIHJlLXJ1biB0aGUgbW9kZWwKIyBJIGFtIG5vdCBhIGZhbiBvZiB0aGlzIC0gd2UnbGwgbG9vayBhdCBvdGhlciBhcHByb2FjaGVzIG5leHQgd2VlayEKIyBhbmQgcmVwZWF0IHRoZSB2YWxpZGF0aW9uCiMgTGV0J3MgZml0IGEgbGluZWFyIG1vZGVsIG5vbmV0aGVsZXNzCmBgYHtyfQptdXNzZWwubG0xIDwtIGxtKFNQRUNJRVMgfiBsb2cxMChBUkVBKSwgZGF0YSA9IE11c3NlbCkKIyBsb29rIGF0IGl0CnN1bW1hcnkobXVzc2VsLmxtMSkKYGBgCiMgTm93IGNoZWNrIGFzc3VtcHRpb24gYnkgdXNpbmcgUidzIGluYnVpbHQgbW9kZWwgdmFsaWRhdGlvbiBwbG90IGRlZmF1bHRzCiMgc2V0IGdyYXBoaWNzIHBhcmFtZXRlcnMgYmVjYXVzZSB3ZSB3YW50IGFsbCB0aGUgcGxvdHMgb24gb25lIGdyYXBoaWMKYGBge3J9CmF1dG9wbG90KG11c3NlbC5sbTEpCmBgYAojIFJlc2lkdWFscyB2IEZpdHRlZCBhcmUgYmV0dGVyIGJ1dCB0aGVyZSBpcyBzdGlsbCBhIGJpdCBvZiB3ZWRnZSBhdCBoaWdoZXIgZml0dGVkIHZhbHVlcwojIHFxcGxvdCBpcyBhIGJldHRlcgojIFNjYWxlLUxvY2F0aW9uIHBsb3QgaW5kaWNhdGVzIGEgc2xpZ2h0IHdlZGdlIHdpdGggaGlnaGVyIHZhbHVlcwojIENvb2sgZGlzdGFuY2UgLyBsZXZlcmFnZSBsb29rcyBpbXByb3ZlZAoKIyBGSU5BTCBWQUxJREFUSU9OIFRBU0sgLSByZXNpZHVhbHMgYWdhaW5zdCBleHBsYW5hdG9yeSB2YXJpYWJsZQpgYGB7cn0KZ2dwbG90KGZvcnRpZnkobXVzc2VsLmxtMSwgTXVzc2VsKSwgYWVzKEFSRUEsIC5zdGRyZXNpZCkpICsKICBnZW9tX3BvaW50KCkgKyBnZW9tX3Ntb290aChzZSA9IEZBTFNFKQpgYGAKIyBUaGlzIGluZGljYXRlcyBhIGZldyBsYXJnZSB2YWx1ZXMgYW5kIGEgc2xpZ2h0IHdlZGdlIGR1ZSB0byBudW1lcm91cyBzbWFsbCBwYXRjaGVzCiMgQ29uY2x1c2lvbiB3ZSByZWplY3QgdGhlIG1vZGVsCgojIFRyeSBsb2cxMCBvbiB0aGUgcmVzcG9uc2UgLSBub3QgdW51c3VhbCB3aXRoIGFidW5kYW5jZSBkYXRhLgojIFRoZXJlIGFyZSBubyB6ZXJvcyBzbyB3ZSBkb24ndCBuZWVkIGFuIG9mZnNldCBvZiAwLjAxIG9yIHNvbWV0aGluZyBzaW1pbGFyCiMgTGV0J3MgZml0IGEgbGluZWFyIG1vZGVsIG5vbmV0aGVsZXNzCmBgYHtyfQptdXNzZWwubG0yIDwtIGxtKGxvZzEwKElORElWKSB+IGxvZzEwKEFSRUEpLCBkYXRhID0gTXVzc2VsKQojIGxvb2sgYXQgaXQKc3VtbWFyeShtdXNzZWwubG0yKQpgYGAKIyBOb3cgY2hlY2sgYXNzdW1wdGlvbiAKYGBge3J9CmF1dG9wbG90KG11c3NlbC5sbTIpCmBgYAojIFJlc2lkdWFscyB2IEZpdHRlZCBhcmUgbXVjaCBiZXR0ZXIgCiMgcXFwbG90IGlzIG9rYXkgLSBzbGlnaHQgaXNzdWUgb24gbG93ZXIgdmFsdWVzCiMgU2NhbGUtTG9jYXRpb24gcGxvdCBpcyBmaW5lCiMgQ29vayBkaXN0YW5jZSAvIGxldmVyYWdlIGxvb2tzIG9rYXkKCiMgRklOQUwgVkFMSURBVElPTiBUQVNLIC0gcmVzaWR1YWxzIGFnYWluc3QgZXhwbGFuYXRvcnkgdmFyaWFibGUKYGBge3J9CmdncGxvdChmb3J0aWZ5KG11c3NlbC5sbTIsIE11c3NlbCksIGFlcyhBUkVBLCAuc3RkcmVzaWQpKSArCiAgZ2VvbV9wb2ludCgpIApgYGAKIyBUaGlzIGlzIGJldHRlciBidXQgc3RpbGwgYSBzbGlnaHQgaHVtcAojIENvbmNsdXNpb24gd2UgYWNjZXB0IHRoZSBtb2RlbAoKIyBwbG90IHRoZSBmaW5hbCBtb2RlbCBpbiBnZ3Bsb3QuLi4KYGBge3J9CnAgPC0gZ2dwbG90KE11c3NlbCwgYWVzKEFSRUEsSU5ESVYpKSArIAogIGdlb21fcG9pbnQoY29sID0gImdyZXkiKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtLCBjb2wgPSAiYmxhY2siKSArIAogIGFubm90YXRlKGdlb20gPSAidGV4dCIsIHggPSAxMDAwLCB5ID0gMzAsCiAgICAgICAgICAgbGFiZWwgPSAibG9nMTAoSU5ESVYpID0gMC44MzUgKyBsb2cxMChBUkVBKSAtIDAuNTc2XG5bQWRqLiBSMiA9IDAuODEwOF0iLCBoanVzdCA9IDApICAjIGFkZHMgdGV4dCAoTk9URSBcbiBtZWFucyBzdGFydCBuZXcgbGluZSkKcCArIHNjYWxlX3hfY29udGludW91cyh0cmFucyA9ICdsb2cxMCcpICsgc2NhbGVfeV9jb250aW51b3VzKHRyYW5zID0gJ2xvZzEwJykgKyAjIFRoZXNlIGNvbW1hbmRzIHNjYWxlIHRoZSBheGVzCiAgYW5ub3RhdGlvbl9sb2d0aWNrcyhzaWRlcz0ibGIiKSAjIFRoaXMgYWRkcyBsb2cxMCB0aWNrIG1hcmtzCmBgYApOT1RFOiB0aGUgbG9nIGF4ZXMgdXNlIHRoZSBTY2FsZXMgbGlicmFyeSBbc2VlIGFib3ZlXQoKI1Bsb3QgdGhlIGdyYXBoIGFkZCBlcXVhdGlvbnMgaW4gYmFzZSBSCmBgYHtyfQpwbG90KGxvZzEwKElORElWKSB+IGxvZzEwKEFSRUEpLCBkYXRhID0gTXVzc2VsLAogICAgIHhsYWIgPSAiTG9nIE11c3NlbCBjbHVtcCBhcmVhIChtbTIpIiwKICAgICB5bGFiID0gIkxvZyBOdW1iZXIgb2YgSW5kaXZpZHVhbHMiLAogICAgIHBjaCA9IDIxLCBjb2wgPSAiZ3JleSIsIGJnID0gImdyZXkiKSAjIFdlJ3ZlIGxlZnQgdGhlIGF4ZXMgb24KIyBhZGQgdGhlIHJlZ3Jlc3Npb24gbGluZSBmcm9tIHRoZSBtb2RlbCAoZmFpdGhmdWwubG0pIHVzaW5nIGFibGluZS4uLi4uCmFibGluZShtdXNzZWwubG0yLCBjb2w9ImJsYWNrIikKIyBhZGQgdGhlIGVxdWF0aW9uCnRleHQoNC4wLCAxLjQsIGV4cHJlc3Npb24ocGFzdGUoTG9nWzEwXSwgIklORElWID0gMC44MzUiLCBsb2dbMTBdLCAiQVJFQSAtIDAuNTc2IiwgcG9zID0gMikpLCBjZXggPSAuNykKIyBhZGQgci1zcXVhcmUgdmFsdWUKdGV4dCg0LjAsIDEuMywgZXhwcmVzc2lvbihwYXN0ZShSXjIgPT0gMC44NTIpKSwgY2V4ID0gLjcpICMgYWRkIGluIHRleHQgdXNpbmcgdGhlIGV4cHJlc3Npb24vcGFzdGUgZnVuY3Rpb25zCiMgY3JlYXRlIGEgc2VxdWVuY2Ugb2YgMTAwMCBudW1iZXIgc3Bhbm5pbmcgdGhlIHJhbmdlIG9mIGh1bWlkaXRpZXMgKG1pbiB0byBtYXgpCnggPC0gc2VxKG1pbihNdXNzZWwkQVJFQSksIG1heChNdXNzZWwkQVJFQSksIGw9MTAwMCkgICMgbm90aWNlIHRoaXMgaXMgYW4gJ2wnID0gbGVuZ3RoLiBOT1QgYSAxISEhISEhIQojZm9yIGVhY2ggdmFsdWUgb2YgeCwgY2FsY3VsYXRlIHRoZSB1cHBlciBhbmQgbG93ZXIgOTUlIGNvbmZpZGVuY2UKeTwtcHJlZGljdChtdXNzZWwubG0yLCBkYXRhLmZyYW1lKEFSRUE9eCksIGludGVydmFsPSJjIikKI3Bsb3QgdGhlIHVwcGVyIGFuZCBsb3dlciA5NSUgY29uZmlkZW5jZSBsaW1pdHMKbWF0bGluZXMobG9nMTAoeCkseSwgbHR5PTMsIGNvbD0iYmxhY2siKSAjIFRoaXMgZnVuY3Rpb24gYWRkIHRoZSBDSXMsIGx0eSA9IGxpbmUgdHlwZSAoZGFzaGVkKSAKYGBgCiMgYWRkIGluIGdncGxvdCBjb2RlLi4uLgpgYGB7cn0KcCA8LSBnZ3Bsb3QoTXVzc2VsLCBhZXMoeD1sb2cxMChBUkVBKSwgeT1sb2cxMChJTkRJVikpKSArIAogIGdlb21fcG9pbnQoY29sID0gImJsdWUiKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtLCBjb2wgPSAiYmxhY2siKSArIAogIGFubm90YXRlKGdlb20gPSAidGV4dCIsIHggPSAyLjUsIHkgPSAzLAogICAgICAgICAgIGxhYmVsID0gIkxvZzEwSU5ESVYgPSAwLjgzNSArIGxvZzEwQVJFQSAtIDAuNTc2XG5BZGouIFIyID0gMC44NTIiLAogICAgICAgICAgIGhqdXN0ID0gMCkKcCArIHhsYWIoIkxvZyBNdXNzZWwgY2x1bXAgYXJlYSAobW0yKSIpICsgeWxhYigiTG9nIG51bWJlciBvZiBpbmRpdmlkdWFscyIpCmBgYAojIDMuIEFOQ09WQSBvbiBjb21wZW5zYXRpb24gZGF0YXNldAojIEp1c3Qgc28geW91IGhhdmUgYSBmcmFtZSBvZiByZWZlcmVuY2UgZ29pbmcgZm9yd2FyZDsKIyB0aGUgY29tcGVuc2F0aW9uIGRhdGEgYXJlIGFib3V0IHRoZSBwcm9kdWN0aW9uIG9mIGZydWl0IChhcHBsZXMsIGtnKSAKIyBvbiByb290c3RvY2tzIG9mIGRpZmZlcmVudCB3aWR0aHMgKG1tOyB0aGUgdG9wcyBhcmUgZ3JhZnRlZCBvbnRvIHJvb3RzdG9ja3MpLiAKIyBGdXJ0aGVybW9yZSwgc29tZSB0cmVlcyBhcmUgaW4gcGFydHMgb2YgdGhlIG9yY2hhcmQgdGhhdCBhbGxvdyBncmF6aW5nIGJ5IGNhdHRsZSwgCiMgYW5kIG90aGVycyBhcmUgaW4gcGFydHMgZnJlZSBmcm9tIGdyYXppbmcuIEdyYXppbmcgbWF5IHJlZHVjZSB0aGUgYW1vdW50IG9mIGdyYXNzLCAKIyB3aGljaCBtaWdodCBjb21wZXRlIHdpdGggdGhlIGFwcGxlIHRyZWVzIGZvciByZXNvdXJjZXMuCgojIExvYWQgZmlsZQpgYGB7cn0KQ29tcGVuc2F0aW9uIDwtIHJlYWQuY3N2KGZpbGUuY2hvb3NlKCkpCmBgYAojIGxvb2sgYXQgZGF0YQpgYGB7cn0Kc3RyKENvbXBlbnNhdGlvbikKYGBgCgpgYGB7cn0KQ29tcGVuc2F0aW9uJEdyYXppbmcgPC0gYXMuZmFjdG9yKENvbXBlbnNhdGlvbiRHcmF6aW5nKSAjIFdlIG5lZWQgdGhpcyB0byBiZSBhIGZhY3RvciBmb3IgYW4gQU5DT1ZBCmBgYApQbG90IGl0CmBgYHtyfQojIFBsb3QgaXQuLi4uCnBsb3QoRnJ1aXQgfiBSb290LCBkYXRhID0gQ29tcGVuc2F0aW9uLCBwY2ggPSAxOSxjZXggPSAxLjUsCiAgICAgY29sID0gYygiQmxhY2siLCAiUmVkIilbQ29tcGVuc2F0aW9uJEdyYXppbmddLAogICAgIHhsYWIgPSBsaXN0KCJSb290IGJpb21hc3MgKG1tKSIsIGNleCA9IDEuMiksCiAgICAgeWxhYiA9IGxpc3QoIkZydWl0IFByb2R1Y3Rpb24gKGtnKSIsIGNleCA9IDEuMikpCiMgTm93IGFkZCBhIGxlZ2VuZApsZWdlbmQoNSwgMTE1LCBsZWdlbmQgPSBjKCJHcmF6ZWQiLCAiVW5ncmF6ZWQiKSwKICAgICAgIGNvbCA9IGMoImJsYWNrIiwgInJlZCIpLCBwY2ggPSAxOSkKYGBgCgpPciBpbiBjb3Bsb3QKYGBge3J9CmNvcGxvdChSb290fiBGcnVpdCB8IEdyYXppbmcsIGRhdGEgPUNvbXBlbnNhdGlvbikgIyBHcmF6ZWQgcGxhbnRzIGhhdmUgaGlnaGVyIHJvb3QgYmlvbWFzcy4gCgpgYGAKIyBZb3UgY2FuIGRvIHRoaXMgaXMgbGF0dGljZSB0b28KYGBge3J9CmJveHBsb3QoUm9vdCB+IEdyYXppbmcsIGRhdGEgPSBDb21wZW5zYXRpb24pICMgVGhlc2UgbG9vayBmaW5lCmJveHBsb3QoRnJ1aXQgfiBHcmF6aW5nLCBkYXRhID0gQ29tcGVuc2F0aW9uKSMgVGhlc2UgbG9vayBmaW5lCmBgYAojIFlvdSBtaWdodCBhbHNvIGRvIHNvbWUgUVEtcGxvdHMgaGVyZS4uLi4ub3IgcGxvdCB0byBjaGVjayBob21vZ2VuZWl0eSBvZiB2YXJpYW5jZXMgCiMgYnV0IHdlJ2xsIGxlYXZlIHRoYXQgZm9yIHZhbGlkYXRpb24uLi4uCgojIFJ1biBBTkNPVkEKYGBge3J9CkNvbXBlbnNhdGlvbi5sbSA8LSBsbShGcnVpdCB+ICBHcmF6aW5nKlJvb3QsIGRhdGE9Q29tcGVuc2F0aW9uKSAKYGBgCiMgVmFsaWRhdGUgbW9kZWwgdG8gY2hlY2sgYXNzdW1wdGlvbnMKYGBge3J9CmF1dG9wbG90KENvbXBlbnNhdGlvbi5sbSkKYGBgCiMgVGhpcyBsb29rcyBwcmV0dHkgZGVjZW50LiBTbGlnaHQgY29uY2VybiBvdmVyIFFRLXBsb3QgYnV0IGl0J3Mgbm90IGEgbWFzc2l2ZSBwcm9ibGVtLgoKI0xvb2sgYXQgbW9kZWwgb3V0Y29tZXMKYGBge3J9CmFub3ZhKENvbXBlbnNhdGlvbi5sbSkKYGBgCiMgQW5vdmEgc2hvd3MgdGhhdCBib3RoIFJvb3QgYW5kIEZydWl0IGFyZSBzaWduaWZpY2FudCB0ZXJtcwojIEJ1dCB0aGF0IHRoZSBpbnRlcmFjdGlvbiBpc24ndC4uLi4KCmBgYHtyfQpzdW1tYXJ5KENvbXBlbnNhdGlvbi5sbSkgCmBgYAojIERhdGEgaW5kaWNhdGUgZnJ1aXQgZGlmZmVycyBieSBncmF6aW5nIAojIE5vIGludGVyYWN0aW9uIHRlcm0gaS5lLiBzbG9wZSBmb3IgZmFjdG9yIEdyYXppbmcgYXJlIHRoZSBzYW1lCiMgTG9vayBhdCB0aGUgZXhhbXBsZSBpbiB0aGUgbGVjdHVyZSA2IHRvIGZpZ3VyZSBvdXQgdGhlIGludGVyY2VwdCBhbmQgc2xvcGUgZGlmZmVyZW5jZXMsIGJ1dCBoZXJlIHdlIGdvOgoKIyBUaGUgaW50ZXJjZXB0IChmaXJzdCByb3cgaW4gdGhlIHN1bW1hcnkgb3V0cHV0KSBpcyB0aGUgaW50ZXJjZXB0IGZvciBncmF6ZWQgc2FtcGxlcyBiZWNhdXNlIGdyYXplZCAoaS5lIEcpCiMgY29tZXMgYmVmb3JlIHVuZ3JhemVkIChpLmUuIFUpIGluIHRoZSBhbHBoYWJldCBhbmQgUiB1c2VzIGFuIGFscGhhbnVtZXJpYyBjYWxsIG9uIGZhY3RvciBkYXRhLiAKIyBUaGUgMm5kIGxpbmUgR3JhemluZ1VuZ3JhemVkIGlzIHRoZSBkaWZmZXJlbmNlIGluIHRoZSBpbnRlcmNlcHRzLiBTbyBVbmdyYXplZCBpcyAzMC44MDYgbGFyZ2VyLiBNZWFuaW5nIDMwLjggbW9yZSBzZWVkcyBhcmUgcHJvZHVjZWQgYnkgZ3JhemVkIHBsYW50cwojIENhbGN1bGF0ZSB0aGUgaW50ZXJjZXB0IGZvciBVbmdyYXplZApgYGB7cn0KLTEyNS4xNzMgICsgMzAuODA2ICMgPSAtOTQuMzY3CmBgYAojIHRoZSB0aGlyZCBsaW5lIGlzIHNsb3BlIGZvciByb290CiMgdGhlIGZvdXJ0aCBsaW5lIEdyYXppbmdVbmdyYXplZDpSb290IGlzIHRoZSBkaWZmZXJlbmNlIGluIHNsb3BlcyBiZXR3ZWVuIEdyYXplZCBhbmQgVW5ncmF6ZWQgPSAwLjc1Niwgd2hpY2ggaXMgdGlueQoKIyB0aGUgY29lZmZpY2llbnRzIHNob3cgdGhpcy4uLi4KYGBge3J9CmNvZWYoQ29tcGVuc2F0aW9uLmxtKQpgYGAKIyBOb3cgbGV0cyBhZGQgbGluZXMgdG8gdGhlIGdyYXBocy4gV2UgY2FuIGRvIGl0IG1hbnkgd2F5cyAtIHNvIGhlcmUgaXMgYW5vdGhlciBvbmUhCiMgUm91dGUgb25lIC0gdXNpbmcgYWJsaW5lCmBgYHtyfQpwbG90KEZydWl0IH4gUm9vdCwgZGF0YSA9IENvbXBlbnNhdGlvbiwgcGNoID0gMTksY2V4ID0gMS41LAogICAgIGNvbCA9IGMoIkJsYWNrIiwgIlJlZCIpW0NvbXBlbnNhdGlvbiRHcmF6aW5nXSwKICAgICB4bGFiID0gbGlzdCgiUm9vdCBiaW9tYXNzIChtbSkiLCBjZXggPSAxLjIpLAogICAgIHlsYWIgPSBsaXN0KCJGcnVpdCBwcm9kdWN0aW9uIChrZykiLCBjZXggPSAxLjIpKQojIE5vdyBhZGQgYSBsZWdlbmQKbGVnZW5kKDUsIDExNSwgbGVnZW5kID0gYygiR3JhemVkIiwgIlVuZ3JhemVkIiksCiAgICAgICBjb2wgPSBjKCJibGFjayIsICJyZWQiKSwgcGNoID0gMTkpCiMgYWRkIGFibGluZXMuLi4ud2UnbGwgZG8gaXQgbWFudWFsbHkgdXNpbmcgdGhlIHNsb3BlcyBhbmQgaW50ZXJjZXB0cyBidXQgeW91IGNhbiB1c2UgY29lZmY3KCkgc2VlIGJlbG93LgphYmxpbmUoLTEyNS4xNzMsIDIzLjI0MCkKYWJsaW5lKC0xMjUuMTczKzMwLjgwNSwgMjMuMjQwKzAuNzU2LCBjb2w9ICJyZWQiKQpgYGAKIyBQbG90IHVzaW5nIGNvZWZmaWNpZW50cwpgYGB7cn0KQ29tcGVuc2F0aW9uLmxtJGNvZWZmWzFdICMgcmVncmVzc2lvbiBjb2VmZmljaWVudCBmb3IgZ3JhemVkIGludGVyY2VwdApDb21wZW5zYXRpb24ubG0kY29lZmZbMl0gIyByZWdyZXNzaW9uIGNvZWZmaWNpZW50IGZvciBncmF6ZWQgc2xvcGUKQ29tcGVuc2F0aW9uLmxtJGNvZWZmWzNdICMgcmVncmVzc2lvbiBjb2VmZmljaWVudCBmb3IgZGlmZiBpbiBncmF6ZWQvdW5ncmF6ZWQgaW50ZXJjZXB0CkNvbXBlbnNhdGlvbi5sbSRjb2VmZls0XSAjIHJlZ3Jlc3Npb24gY29lZmZpY2llbnQgZm9yIGRpZmYgaW4gZ3JhemVkL3VuZ3JhemVkIHNsb3BlCnBsb3QoRnJ1aXQgfiBSb290LCBkYXRhID0gQ29tcGVuc2F0aW9uLCBwY2ggPSAxOSxjZXggPSAxLjUsCiAgICAgY29sID0gYygiQmxhY2siLCAiUmVkIilbQ29tcGVuc2F0aW9uJEdyYXppbmddLAogICAgIHhsYWIgPSBsaXN0KCJSb290IGJpb21hc3MgKG1tKSIsIGNleCA9IDEuMiksCiAgICAgeWxhYiA9IGxpc3QoIkZydWl0IFByb2R1Y3Rpb24gKGtnKSIsIGNleCA9IDEuMikpCiMgTm93IGFkZCBhIGxlZ2VuZApsZWdlbmQoNSwgMTE1LCBsZWdlbmQgPSBjKCJHcmF6ZWQiLCAiVW5ncmF6ZWQiKSwKICAgICAgIGNvbCA9IGMoImJsYWNrIiwgInJlZCIpLCBwY2ggPSAxOSkKIyBhZGQgYWJsaW5lcy4uLi51c2luZyBjb2VmZmljaWVudHMgLSBjb2VmZigpCmFibGluZShjb2VmKENvbXBlbnNhdGlvbi5sbSlbMV0sIGNvZWYoQ29tcGVuc2F0aW9uLmxtKVszXSkgCiMgTm93IGFkZCB0aGUgc3VtbWVyIHJlZ3Jlc3Npb24gbGluZQphYmxpbmUoY29lZihDb21wZW5zYXRpb24ubG0pWzFdICsgY29lZihDb21wZW5zYXRpb24ubG0pWzJdLAkKICAgICAgIGNvZWYoQ29tcGVuc2F0aW9uLmxtKVszXSArIGNvZWYoQ29tcGVuc2F0aW9uLmxtKVs0XSwJCiAgICAgICBjb2wgPSAicmVkIikKYGBgCiMgZG8gc29tZSBwcmVkaWN0aW9uLi4uLmFuZCBwbG90Li4uLnRoaXMgaXMgeWV0IGFub3RoZXIgd2F5IG9mIGRvaW5nIGl0CiNwcm9kdWNlIGJhc2UgcGxvdCAKYGBge3J9CnhzIDwtIHNlcSgwLCAxMiwgbCA9IDEwMCkKcGxvdChGcnVpdCB+IFJvb3QsIGRhdGEgPSBDb21wZW5zYXRpb24sIHhsYWIgPSAiUm9vdCBiaW9tYXNzIChtbSkiLCB5bGFiID0gIkZydWl0IFByb2R1Y3Rpb24gKGtnKSIpCiMgUGxvdCB0aGUgcG9pbnRzIGFuZCBwcmVkaWN0ZWQgdHJlbmRzICh1c2luZyBzZSkKcG9pbnRzKEZydWl0IH4gUm9vdCwgZGF0YSA9IENvbXBlbnNhdGlvbiwgc3Vic2V0ID0gR3JhemluZyA9PSAiR3JhemVkIiwgcGNoID0gMTkpCnByZWQgPC0gcHJlZGljdChDb21wZW5zYXRpb24ubG0sIHR5cGUgPSAicmVzcG9uc2UiLCBzZSA9IFRSVUUsIG5ld2RhdGEgPSBkYXRhLmZyYW1lKFJvb3QgPSB4cywgR3JhemluZyA9ICJHcmF6ZWQiLCBSb290ID0gbWVhbihDb21wZW5zYXRpb24kUm9vdCkpKQpsaW5lcyhwcmVkJGZpdCB+IHhzKQpwb2ludHMoRnJ1aXQgfiBSb290LCBkYXRhID0gQ29tcGVuc2F0aW9uLCBzdWJzZXQgPSBHcmF6aW5nID09ICJVbmdyYXplZCIsIHBjaCA9IDE5LCBjb2wgPSAicmVkIikKcHJlZCA8LSBwcmVkaWN0KENvbXBlbnNhdGlvbi5sbSwgdHlwZSA9ICJyZXNwb25zZSIsIHNlID0gVFJVRSwgbmV3ZGF0YSA9IGRhdGEuZnJhbWUoUm9vdCA9IHhzLCBHcmF6aW5nID0gIlVuZ3JhemVkIiwgUm9vdCA9IG1lYW4oQ29tcGVuc2F0aW9uJFJvb3QpKSkKbGluZXMocHJlZCRmaXQgfiB4cywgY29sID0gInJlZCIpCmxlZ2VuZCgidG9wbGVmdCIsIGxlZ2VuZCA9IGMoIkdyYXplZCIsICJVbmdyYXplZCIpLCBwY2ggPSBjKDE5LCAxOSksIGNvbCA9IGMoInJlZCIsImJsYWNrIiksIHRpdGxlID0gIkZydWl0IFByb2R1Y3Rpb24iLCBidHkgPSAibiIpCmJveChidHkgPSAibCIpCmBgYAojIFBsb3QgdGhlIHBvaW50cyBhbmQgcHJlZGljdGVkIHRyZW5kcyAodXNpbmcgZ2dwbG90MikuIEEgZmFpciBiaXQgZWFzaWVyLi4uLi5OT1RFIC0geW91J2QgbmVlZCB0byB0aWR5IHVwIHRoZSBsYWJlbHMgYW5kIHRoZSBsaWtlLi4uCmBgYHtyfQpnZ3Bsb3QoQ29tcGVuc2F0aW9uLCBhZXMoeD1Sb290LCB5PUZydWl0LCBjb2xvcj1mYWN0b3IoR3JhemluZykpKSArCiAgZ2VvbV9wb2ludCgpICsgCiAgZ2VvbV9zbW9vdGgobWV0aG9kPWxtKQpgYGA=